﻿using Colorful.Furniture.CommonDto;
using Colorful.Furniture.Extensions;
using FreeSql;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Colorful.Furniture.ErpInventoryManagement;

namespace Colorful.Furniture.SysManagement;

/// <summary>
/// 数据字典
/// </summary>
public class DictionaryAppService : ApplicationService
{
    private readonly IBaseRepository<SysDictionary> _sysDictionaryRepository;
    private readonly ILogger<DictionaryAppService> _logger;
    private readonly IBaseRepository<Inventory> _inventoryRepository;
    private readonly IFreeSql _freeSql;

    public DictionaryAppService(
        IBaseRepository<SysDictionary> sysDictionaryRepository,
        ILogger<DictionaryAppService> logger,
        IBaseRepository<Inventory> inventoryRepository,
        IFreeSql freeSql)
    {
        _sysDictionaryRepository = sysDictionaryRepository;
        _logger = logger;
        _inventoryRepository = inventoryRepository;
        _freeSql = freeSql;
    }

    /// <summary>
    ///  数据字典树
    /// </summary>
    /// <returns></returns>
    public async Task<List<TreeOutputDto<Guid>>> TreeAsync()
    {
        //获取数据字典树形列表
        var dictionaryTreeList = await _sysDictionaryRepository
            .Where(x => !x.IsDeleted)
            .OrderBy(x => x.Sort)
            .ToTreeListAsync();

        var result = ObjectMapper.Map<List<SysDictionary>, List<TreeOutputDto<Guid>>>(dictionaryTreeList);

        return result;
    }

    /// <summary>
    ///  保存
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<bool> SaveAsync(SysDictionarySaveInputOutputDto input)
    {
        //从dto中自动映射
        var model = ObjectMapper.Map<SysDictionarySaveInputOutputDto, SysDictionary>(input);

        if (!string.IsNullOrWhiteSpace(input.Code))
        {
            var codeExist = await _sysDictionaryRepository
                .Where(x => x.Code == input.Code && x.Id != input.Id)
                .CountAsync();

            if (codeExist > 0)
                throw new UserFriendlyException($"数据字典代码[{input.Code}]已存在，请更换", "400");
        }

        //处理数据字典的value值
        var parentDictionary = await _sysDictionaryRepository
            .Where(x => x.Id == input.ParentId)
            .IncludeMany(x => x.Children, x => x.OrderByDescending(y => y.Value))
            .ToOneAsync(x => new
            {
                x.Value,
                x.Children
            });

        if (parentDictionary != null)
        {
            var children = parentDictionary.Children;

            var maxChildValue = 1001L;

            if (children.Any())
            {
                maxChildValue = children.First().Value.ToLong(1001) + 1;
            }

            //处理序号
            if (string.IsNullOrWhiteSpace(input.Sort))
            {
                var sort = children.Count + 1;
                model.Sort = sort;
            }

            model.Value = maxChildValue.ToString();
        }

        //修改
        if (!input.Id.IsNull())
        {
            var updateModel = new SysDictionary
            {
                // ReSharper disable once PossibleInvalidOperationException
                Id = input.Id.Value
            };

            _sysDictionaryRepository.Attach(updateModel);

            updateModel = ObjectMapper.Map<SysDictionarySaveInputOutputDto, SysDictionary>(input);

            await _sysDictionaryRepository.UpdateAsync(updateModel);
        }
        else
        {
            await _sysDictionaryRepository.InsertAsync(model);
        }

        return true;
    }

    /// <summary>
    ///  获取表单编辑信息
    /// </summary>
    /// <returns></returns>
    public async Task<SysDictionaryFormOutputDto> GetFormAsync(Guid id)
    {
        var sysDictionary = await _sysDictionaryRepository
            .Where(x => x.Id == id)
            .ToOneAsync();

        if (sysDictionary == null)
            return new SysDictionaryFormOutputDto();

        var result = ObjectMapper.Map<SysDictionary, SysDictionaryFormOutputDto>(sysDictionary);

        return result;
    }

    /// <summary>
    ///  删除
    /// </summary>
    /// <returns></returns>
    [HttpDelete]
    public async Task<bool> DeleteAsync([FromBody] List<Guid> ids)
    {
        //判断删除是否是原材料下面数据
        var existList = (await _inventoryRepository
            .Where(x => ids.Contains(x.CategoryId ?? Guid.Empty))
            .ToListAsync(x => new
            {
                x.Category
            })).GroupBy(x => x.Category)
            .Select(x => x.Key)
            .ToList();

        if (existList.Any())
            throw new UserFriendlyException($"库存产品分类 {string.Join(",", existList)} 下有产品数据，不能删除");

        var result = await _sysDictionaryRepository.UpdateDiy
            .Set(x => x.IsDeleted, true)
            .Where(x => ids.Contains(x.Id) && !x.IsSys)
            .ExecuteAffrowsAsync();

        _logger.LogInformation($"逻辑删除数据字典：{result} 条");

        return result > 0;
    }

    /// <summary>
    ///  二级级联
    /// </summary>
    /// <param name="pCode">父级code</param>
    /// <param name="code">当前code</param>
    /// <param name="isIncludeSelf">是否包含code对应的</param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public async Task<List<CascadeOutputDto>> GetCascadeListAsync(string pCode, string code = null, bool isIncludeSelf = true)
    {
        if (string.IsNullOrWhiteSpace(pCode))
            throw new ArgumentNullException(nameof(pCode));

        //获取需要开始递归的父级数据
        var dictionaryParent = await _sysDictionaryRepository
            .Where(x => x.Code.ToLower() == pCode.ToLower())
            .ToOneAsync();

        if (dictionaryParent == null)
        {
            return new List<CascadeOutputDto>();
        }

        //获取级联树形数据
        var cascadeTreeOneList = await _sysDictionaryRepository
            .WhereIf(isIncludeSelf, x => x.ParentId == dictionaryParent.Id)
            .WhereIf(!string.IsNullOrWhiteSpace(code) && isIncludeSelf, x => x.Code.ToLower() == code.ToLower())
            .WhereIf(!isIncludeSelf, x => x.Code != code && x.Parent.Code.ToLower() == code.ToLower())
            .IncludeMany(x => x.Children)
            .OrderBy(x => x.Sort)
            .ToListAsync();

        //解决element ui Cascade组件在有children:[]的时候默认会多出一个列选项
        var cascadeTree = cascadeTreeOneList
            .Select(x => new CascadeOutputDto
            {
                Value = x.Id,
                Code = x.Code,
                Icon = x.Icon,
                ParentId = x.ParentId,
                Label = x.Title,
                Value1 = x.Value,
                Children = x.Children.Any() ? x.Children.Select(y => new CascadeOutputDto
                {
                    Value = y.Id,
                    Code = y.Code,
                    Icon = y.Icon,
                    Label = y.Title,
                    ParentId = y.ParentId,
                    Value1 = y.Value
                }).ToList() : null
            }).ToList();

        return cascadeTree;
    }


    /// <summary>
    /// 获取选项列表
    /// </summary>
    /// <param name="name">名称</param>
    /// <param name="parentId">父级ID</param>
    /// <returns></returns>
    public async Task<List<OptionOutputIdDto>> GetOptionListByNameAsync(string name, Guid parentId)
    {
        var list = await _freeSql.Select<SysDictionary>()
            .WhereIf(!string.IsNullOrWhiteSpace(name), x => x.Title.Contains(name))
            .Where(x => !x.IsDeleted && x.ParentId == parentId)
            .ToListAsync(x => new OptionOutputIdDto
            {
                Label = x.Title,
                Value = x.Id
            }
            );

        return list;
    }

}